package com.one.rope.mvp.basecore.util;

import java.lang.reflect.Field;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 属性设置
 */
public class FieldUtils {

  public static <T> void setValue(T t, Field field, Object value) throws Exception {
    Class<?> fieldCls = field.getType();
    if (fieldCls.isPrimitive()) {
      field.set(t, castType(fieldCls, value));
    } else {
      field.set(t, field.getType().cast(value));
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T castType(Class<T> clazz, Object object) {
    return (T) object;
  }

  /**
   * 字符串转换成其它类型
   */
  public static Object stringToType(Class<?> clazz, String value) {

    if (boolean.class == clazz || Boolean.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return false;
      }
      return Boolean.parseBoolean(value);
    }

    if (byte.class == clazz || Byte.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return Byte.parseByte("0");
      }
      return Byte.parseByte(value);
    }
    if (short.class == clazz || Short.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return Short.valueOf((short) 0);
      }
      return Short.parseShort(value);
    }
    if (int.class == clazz || Integer.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return new Integer(0);
      }
      return Integer.parseInt(value);
    }

    if (long.class == clazz || Long.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return 0L;
      }
      return Long.parseLong(value);
    }
    if (float.class == clazz || Float.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return Float.valueOf(0.0f);
      }
      return Float.parseFloat(value);
    }
    if (double.class == clazz || Double.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return Double.valueOf(0.0d);
      }
      return Double.parseDouble(value);
    }
    if (char.class == clazz || Character.class == clazz) {
      if (StringUtils.isNullOrEmpty(value)) {
        return Character.valueOf((char) 0);
      }
      return value.toCharArray();
    }
    return value;
  }

  public static Object defaultValue(Class<?> clazz) {
    if (boolean.class == clazz) {
      return false;
    }
    if (byte.class == clazz) {
      return (byte) 0;
    }
    if (short.class == clazz) {
      return 0;
    }
    if (int.class == clazz) {
      return 0;
    }
    if (long.class == clazz) {
      return 0L;
    }
    if (float.class == clazz) {
      return 0.0;
    }
    if (double.class == clazz) {
      return 0.0d;
    }
    if (char.class == clazz) {
      return (char) 0;
    }
    return null;
  }

  public static Double objectToDouble(Class<?> clazz, Object value) {
    if (boolean.class == clazz) {
      return ((Boolean) value).booleanValue() == true ? 1.0 : 0.0;
    }
    if (byte.class == clazz) {
      return Double.valueOf((Byte) value);
    }
    if (short.class == clazz) {
      return Double.valueOf((Short) value);
    }
    if (int.class == clazz) {
      return Double.valueOf((Integer) value);
    }
    if (long.class == clazz) {
      return Double.valueOf((Long) value);
    }
    if (float.class == clazz) {
      return Double.valueOf((Float) value);
    }
    if (double.class == clazz) {
      return Double.valueOf((Double) value);
    }
    if (char.class == clazz) {
      return Double.valueOf((char) value);
    }
    return Double.parseDouble(value.toString());
  }

  /**
   * 一般的类型转换成字符串
   */
  public static String typeToString(Class<?> clazz, Object value) {
    if (boolean.class == clazz) {
      return String.valueOf((Boolean) value);
    }
    if (byte.class == clazz) {
      return String.valueOf((Byte) value);
    }
    if (short.class == clazz) {
      return String.valueOf((Short) value);
    }
    if (int.class == clazz) {
      return String.valueOf((Integer) value);
    }
    if (long.class == clazz) {
      return String.valueOf((Long) value);
    }
    if (float.class == clazz) {
      return String.valueOf((Float) value);
    }
    if (double.class == clazz) {
      return String.valueOf((Double) value);
    }
    if (char.class == clazz) {
      return String.valueOf((char) value);
    }
    return value.toString();
  }

  public static String typeToRedisString(Class<?> clazz, Object value) {
    if (boolean.class == clazz) {
      return String.valueOf((Boolean) value);
    }
    if (byte.class == clazz) {
      return String.valueOf((Byte) value);
    }
    if (short.class == clazz) {
      return String.valueOf((Short) value);
    }
    if (int.class == clazz) {
      return String.valueOf((Integer) value);
    }
    if (long.class == clazz) {
      return String.valueOf((Long) value);
    }
    if (float.class == clazz) {
      return String.valueOf((Float) value);
    }
    if (double.class == clazz) {
      return String.valueOf((Double) value);
    }
    if (char.class == clazz) {
      return String.valueOf((char) value);
    }

    if (clazz.getName().indexOf("java.") >= 0) {
      return value.toString();
    }

    return JsonUtils.objectToJsonString(value);
  }

  public static Object excelCastString(Class<?> clazz, String value) throws Exception {
    if (boolean.class == clazz) {
      return Boolean.parseBoolean(value);
    }
    if (byte.class == clazz) {
      return Byte.parseByte(value);
    }
    if (short.class == clazz) {
      return Short.parseShort(value);
    }
    if (int.class == clazz) {
      NumberFormat nf = NumberFormat.getInstance();
      return nf.parse(value).intValue();
    }
    if (long.class == clazz) {
      return Long.parseLong(value);
    }
    if (float.class == clazz) {
      return Float.parseFloat(value);
    }
    if (double.class == clazz) {
      return Double.parseDouble(value);
    }
    if (char.class == clazz) {
      return value.toCharArray();
    }
    return value;
  }

  public static <T> List<Field> getFields(Class<T> clz) {
    List<Field> fields = new ArrayList<>();
    Class<?> clazz = clz;
    while (clazz != Object.class) {
      fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
      clazz = clazz.getSuperclass();
    }
    return fields;
  }

  //Modifier.isPublic(m2))
  public static <T> List<Field> getFields(Class<T> clz, ExecuteBoolFunction<Field> function) {
    List<Field> fields = new ArrayList<>();
    Class<?> clazz = clz;
    while (clazz != Object.class) {
      for (Field field : clazz.getDeclaredFields()) {
        if (function.execute(field)) {

          fields.add(field);
        }
      }
      clazz = clazz.getSuperclass();
    }
    return fields;
  }

  /**
   * 获取实例的字段值
   */
  public static Object getInstanceValue(final Object classInstance, final String fieldName)
      throws SecurityException,
      NoSuchFieldException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {

    // Get the private field
    // Field field = classInstance.getClass().getDeclaredField(fieldName);
    Field field = getDeclareField(classInstance.getClass(), fieldName);
    // Allow modification on the field
    field.setAccessible(true);
    // Return the Obect corresponding to the field
    return field.get(classInstance);
  }

  public static Object getInstanceValue(final Object classInstance, Field field) {
    try {
      field.setAccessible(true);
      // Return the Obect corresponding to the field
      return field.get(classInstance);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * 设置实例的值
   */
  public static void setInstanceValue(final Object classInstance, final String fieldName,
      final Object newValue)
      throws SecurityException, NoSuchFieldException, ClassNotFoundException, IllegalArgumentException,
      IllegalAccessException {
    // Get the private field
    Field field = getDeclareField(classInstance.getClass(), fieldName);
    // Allow modification on the field
    field.setAccessible(true);
    // Sets the field to the new value for this instance
    field.set(classInstance, newValue);

  }

  public static void setInstanceValue(final Object classInstance, Field field,
      final Object newValue)
      throws SecurityException, NoSuchFieldException, ClassNotFoundException, IllegalArgumentException,
      IllegalAccessException {

    // Allow modification on the field
    field.setAccessible(true);
    // Sets the field to the new value for this instance
    field.set(classInstance, newValue);

  }

  /**
   * 获取静态变量的值
   */
  public static Object getStaticValue(final String className, final String fieldName)
      throws SecurityException,
      NoSuchFieldException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {

    // Get the private field
    Field field = null;// Class.forName(className).getDeclaredField(fieldName);
    field = getDeclareField(Class.forName(className), fieldName);

    // Allow modification on the field
    field.setAccessible(true);
    // Return the Obect corresponding to the field
    return field.get(Class.forName(className));
  }

  public static <T> T readField(String name, Object target) throws Exception {
    Field field = null;
    Class<?> clazz = target.getClass();
    field = getDeclareField(clazz, name);

    if (field == null) {
      throw new IllegalArgumentException(
          "Cannot find field '" + name + "' in the class hierarchy of " + target.getClass());
    }
    field.setAccessible(true);
    return (T) field.get(target);
  }

  public static Field getDeclareField(Class<?> clazz, String fieldName) {
    Field field = null;
    do {
      try {
        field = clazz.getDeclaredField(fieldName);
      } catch (Exception ex) {
      }

      clazz = clazz.getSuperclass();
    } while (field == null && !clazz.equals(Object.class));
    return field;
  }

  public static void setField(String name, Object target, Object value) throws Exception {
    Field field = null;
    Class<?> clazz = target.getClass();
    field = getDeclareField(clazz, name);
    if (field == null) {
      throw new IllegalArgumentException(
          "Cannot find field '" + name + "' in the class hierarchy of " + target.getClass());
    }
    field.setAccessible(true);
    field.set(target, value);
  }

  @FunctionalInterface
  interface ExecuteBoolFunction<T> {

    /**
     * 运行方法
     */
    boolean execute(T t);
  }

}
